package com.ming.job.xxljob.controller;

import cn.hutool.core.date.DateUtil;
import com.ming.common.beetl.util.Result;
import com.ming.common.xxljob.annotation.PermissionLimit;
import com.ming.job.xxljob.entity.XxlJobGroup;
import com.ming.job.xxljob.entity.XxlJobInfo;
import com.ming.job.xxljob.entity.XxlJobLogReport;
import com.ming.job.xxljob.entity.XxlJobLogReportStatictics;
import com.ming.job.xxljob.vo.XxlJobLogVo;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.query.LambdaQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@RestController
@RequestMapping("/xxljob/report")
public class IvyXxlJobReportController {

    private static final Logger logger = LoggerFactory.getLogger(IvyXxlJobReportController.class);

    @Resource
    private SQLManager sqlManager;

    @PostMapping("/dashboardInfo")
    @PermissionLimit(limit = false)
    public Result<?> dashboardInfo(@RequestBody XxlJobLogVo vo){
        long count = sqlManager.lambdaQuery(XxlJobInfo.class).count();
        int jobInfoCount = (int) count;
        int jobLogCount = 0;
        int jobLogSuccessCount = 0;
        int jobLogFailCount = 0;
        int jobLogRunCount = 0;
        XxlJobLogReport xxlJobLogReport = sqlManager.lambdaQuery(XxlJobLogReport.class).single("SUM(running_count) running_count,SUM(suc_count) suc_count, SUM(fail_count) fail_count");

        if (xxlJobLogReport != null) {
            jobLogCount = xxlJobLogReport.getRunningCount() + xxlJobLogReport.getSucCount() + xxlJobLogReport.getFailCount();
            jobLogSuccessCount = xxlJobLogReport.getSucCount();
            jobLogRunCount = xxlJobLogReport.getRunningCount();
            jobLogFailCount = xxlJobLogReport.getFailCount();
        }

        // executor count
        Set<String> executorAddressSet = new HashSet<String>();

        List<XxlJobGroup> groupList = sqlManager.lambdaQuery(XxlJobGroup.class).asc(XxlJobGroup::getAppName).asc(XxlJobGroup::getTitle).asc(XxlJobGroup::getId).select();
        if (groupList!=null && !groupList.isEmpty()) {
            for (XxlJobGroup group: groupList) {
                if (group.getRegistryList()!=null && !group.getRegistryList().isEmpty()) {
                    executorAddressSet.addAll(group.getRegistryList());
                }
            }
        }

        int executorCount = executorAddressSet.size();

        List<XxlJobLogReportStatictics> list = new ArrayList<>();
        list.add(new XxlJobLogReportStatictics("#ffffff","任务数量",  "调度中心运行的任务数量",jobInfoCount+""));
        list.add(new XxlJobLogReportStatictics("#ffffff","调度次数",  "调度中心触发的调度次数",jobLogCount+""));
        list.add(new XxlJobLogReportStatictics("#ffffff","执行器数量","在线的执行器机器数量",executorCount+""));
        list.add(new XxlJobLogReportStatictics("#00d4bd","成功数量",  "执行成功的任务数量",jobLogSuccessCount+""));
        list.add(new XxlJobLogReportStatictics("#fdd835","进行中数量","执行中的任务数量",jobLogRunCount+""));
        list.add(new XxlJobLogReportStatictics("#ffa1a1","失败数量",  "执行失败的任务数量",jobLogFailCount+""));
        return Result.OK(list);
    }

    @PostMapping("/chartInfo")
    @PermissionLimit(limit = false)
    public Result<?> chartInfo(@RequestBody XxlJobLogVo vo){
        Date startDate = vo.getStartDate();
        Date endDate = vo.getEndDate();
        /*if(startDate == null){
            startDate = DateUtil.date().setField(DateField.HOUR,0).setField(DateField.MINUTE,0).setField(DateField.SECOND,0).setField(DateField.MILLISECOND,0);
        }
        if(endDate == null){
            startDate = DateUtil.date().setField(DateField.HOUR,23).setField(DateField.MINUTE,59).setField(DateField.SECOND,59).setField(DateField.MILLISECOND,999);
        }*/
        // process
        List<String> triggerDayList = new ArrayList<String>();
        List<Integer> triggerDayCountRunningList = new ArrayList<Integer>();
        List<Integer> triggerDayCountSucList = new ArrayList<Integer>();
        List<Integer> triggerDayCountFailList = new ArrayList<Integer>();
        int triggerCountRunningTotal = 0;
        int triggerCountSucTotal = 0;
        int triggerCountFailTotal = 0;

        LambdaQuery<XxlJobLogReport> query = sqlManager.lambdaQuery(XxlJobLogReport.class);
        if(startDate != null && endDate != null){
            query.andBetween(XxlJobLogReport::getTriggerDay,startDate, endDate);
        }else{
            query.andBetween(XxlJobLogReport::getTriggerDay,DateUtil.offsetDay(DateUtil.date(),-15), DateUtil.date());
        }
        query.asc(XxlJobLogReport::getTriggerDay);
        List<XxlJobLogReport> logReportList = query.select();
        if (logReportList!=null && logReportList.size()>0) {
            for (XxlJobLogReport item: logReportList) {
                String day = DateUtil.formatDate(item.getTriggerDay());
                int triggerDayCountRunning = item.getRunningCount();
                int triggerDayCountSuc = item.getSucCount();
                int triggerDayCountFail = item.getFailCount();

                triggerDayList.add(day);
                triggerDayCountRunningList.add(triggerDayCountRunning);
                triggerDayCountSucList.add(triggerDayCountSuc);
                triggerDayCountFailList.add(triggerDayCountFail);

                triggerCountRunningTotal += triggerDayCountRunning;
                triggerCountSucTotal += triggerDayCountSuc;
                triggerCountFailTotal += triggerDayCountFail;
            }
        } else {
            for (int i = -6; i <= 0; i++) {
                triggerDayList.add(DateUtil.formatDate(addDays(new Date(), i)));
                triggerDayCountRunningList.add(0);
                triggerDayCountSucList.add(0);
                triggerDayCountFailList.add(0);
            }
        }

        Map<String, Object> result = new HashMap<String, Object>();
        result.put("triggerDayList", triggerDayList);
        result.put("triggerDayCountRunningList", triggerDayCountRunningList);
        result.put("triggerDayCountSucList", triggerDayCountSucList);
        result.put("triggerDayCountFailList", triggerDayCountFailList);

        int total = triggerCountRunningTotal + triggerCountSucTotal + triggerCountFailTotal;

        if(total != 0){
            int i = BigDecimal.valueOf(triggerCountRunningTotal).divide(BigDecimal.valueOf(total), 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).intValue();
            int j = BigDecimal.valueOf(triggerCountSucTotal).divide(BigDecimal.valueOf(total), 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).intValue();
            int k = BigDecimal.valueOf(triggerCountFailTotal).divide(BigDecimal.valueOf(total), 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).intValue();

            result.put("triggerCountRunningTotal", i);
            result.put("triggerCountSucTotal", j);
            result.put("triggerCountFailTotal", k);
        }else{
            result.put("triggerCountRunningTotal", 0);
            result.put("triggerCountSucTotal", 0);
            result.put("triggerCountFailTotal", 0);
        }
        return Result.OK(result);
    }

    public static Date addDays(final Date date, final int amount) {
        return add(date, Calendar.DAY_OF_MONTH, amount);
    }

    private static Date add(final Date date, final int calendarField, final int amount) {
        if (date == null) {
            return null;
        }
        final Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(calendarField, amount);
        return c.getTime();
    }
}
